/* Copyright (c) 2022 渝州大数据实验室
 *
 * Lanius is licensed under Mulan PSL v2.
 * You can use this software according to the terms and conditions of the Mulan PSL v2.
 * You may obtain a copy of Mulan PSL v2 at:
 *
 *     http://license.coscl.org.cn/MulanPSL2
 *
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 * See the Mulan PSL v2 for more details.
 */
package org.yzbdl.lanius.orchestrate.serv.utils;

import com.jcraft.jsch.ChannelShell;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.JSchException;
import com.jcraft.jsch.Session;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.*;
import java.nio.charset.StandardCharsets;
import java.util.Objects;
import java.util.Properties;

/**
 * ssh连接工具
 * @author zhuhongji@yzbdl.ac.cn
 * @since 2022-04-08 16:49
 */
public class SshUtils {

    private static final Logger logger = LoggerFactory.getLogger(SshUtils.class);

    private static final int SESSION_TIMEOUT = 10000;

    /**
     * 测试服务器连接
     * @param ip ip
     * @param port 端口
     * @param username 账户名
     * @param password 密码
     * @return 连接成功与否
     */
    public static boolean serverTestConnection(String ip, int port, String username, String password) {
        Session sshSession = null;
        try {
            JSch jsch = new JSch();
            sshSession = jsch.getSession(username, ip, port);
            sshSession.setPassword(password);
            sshSession.setTimeout(SESSION_TIMEOUT);
            Properties sshConfig = new Properties();
            // 跳过检测
            sshConfig.put("StrictHostKeyChecking", "no");
            sshSession.setConfig(sshConfig);
            sshSession.connect();
            logger.debug("服务器{}连接已创建。", ip);
            return true;
        } catch (JSchException e) {
            logger.error("连接服务器{}失败:\r\n{}", ip, e.getMessage());
            return false;
        } finally {
            try {
                if (Objects.nonNull(sshSession)) {
                    sshSession.disconnect();
                }
            } catch (Exception e) {
                logger.error("sshSession关闭异常!", e);
            }
        }
    }

    /**
     * 执行shell脚本
     * @param ip ip
     * @param port 端口
     * @param username 账户名
     * @param password 密码
     * @param shell 执行命令
     * @return 执行返回值
     */
    public static String executeCommand(String ip, int port, String username, String password, String... shell) {
        Session sshSession = null;
        ChannelShell channel = null;
        BufferedReader in = null;
        try {
            JSch jsch = new JSch();
            sshSession = jsch.getSession(username, ip, port);
            sshSession.setPassword(password);
            sshSession.setTimeout(SESSION_TIMEOUT);
            Properties sshConfig = new Properties();
            // 跳过检测
            sshConfig.put("StrictHostKeyChecking", "no");
            sshSession.setConfig(sshConfig);
            sshSession.connect();
            logger.debug("服务器{}连接已创建。", ip);
            channel = (ChannelShell)sshSession.openChannel("shell");
            channel.connect();
            InputStream inputStream = channel.getInputStream();
            OutputStream outputStream = channel.getOutputStream();
            PrintWriter printWriter = new PrintWriter(outputStream);

            for (String s : shell) {
                logger.debug("命令：{}", s);
                printWriter.println(s);
            }
            printWriter.println("exit");
            printWriter.flush();

            // 获取解析编码
            in = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8));
            StringBuilder shellMsg = new StringBuilder();
            String msg;
            while ((msg = in.readLine()) != null) {
                if (StringUtils.isNotBlank(msg)) {
                    logger.debug("执行结果：{}", msg);
                    shellMsg.append(msg).append(System.getProperty("line.separator"));
                }
            }
            String backMsg = shellMsg.toString();
            logger.debug(backMsg);
            return backMsg;
        } catch (JSchException e) {
            logger.error("SHELL远程连接失败，请检查配置", e);
        } catch (IOException e) {
            logger.error("文件流操作异常", e);
        } finally {
            try {
                if (Objects.nonNull(sshSession)) {
                    sshSession.disconnect();
                }
            } catch (Exception e) {
                logger.error("sshSession关闭异常!", e);
            }
            try {
                if (Objects.nonNull(channel)) {
                    channel.disconnect();
                }
            } catch (Exception e) {
                logger.error("channel关闭异常!", e);
            }
            try {
                if (Objects.nonNull(in)) {
                    in.close();
                }
            } catch (IOException e) {
                logger.error("IO关闭异常!", e);
            }
        }
        return "";
    }

}
